# coding=utf-8
__all__ = ['IfDoFinal', 'copyResult', 'addResult', 'getResultDf']

from enum import Enum, unique
import numpy as np
import pandas as pd
import json
import math
import pickle
import copy
import ast
import StrUtils

@unique
class IfDoFinal(Enum):
    DoFinal = 1
    DontFinal = 2
    OnlyFinal = 3


def copyResult(_src):
    return _src.data.copy(), _src.extdata.copy(), _src.moredata.copy()


def addResult(_src, data, extdata):
    '''
    numpy数组运算 https://www.cnblogs.com/zhangchaoyang/articles/7040161.html
    '''
    _src.data += data
    _src.extdata += extdata


def getResultDf(_src, xMultiIndex=True, yMultiIndex=True, separator='/', nonVal='.', keepIndexInData=False):
    '''
    getResultDf，行列都是多层时，都设成MultiIndex，方便查找
    '''
    if ((_src.numX == 0) or (_src.numY == 0)):
        return pd.DataFrame()

    len_y = 0
    dict_y = {}
    for key, val in _src.titlesY.items():
        len_y = max(len(val), len_y)
        val_ = []
        for v in val:
            status, str_ = StrUtils.getStatementContent(v, True, '')
            status, s = StrUtils.getStatementContent(str_, True, False)
            if s:
                val_.append(s)
            else:
                if (status != 0):
                    # 角本中刻意把这项设为空(status==0)，则表示放弃当前项的注释，如：
                    # expression // 数据库 //
                    status, str_ = StrUtils.getStatementContent(str_, False, '')
                    val_.append(str_)
        if yMultiIndex:
            dict_y[key] = val_
        else:
            dict_y[key] = separator.join(val_)

    if ((not yMultiIndex) and (len_y > 1)):
        len_y = 1

    len_x = 0
    dict_x = {}
    for key, val in _src.titlesX.items():
        len_x = max(len(val), len_x)
        val_ = []
        for v in val:
            status, str_ = StrUtils.getStatementContent(v, True, '')
            status, s = StrUtils.getStatementContent(str_, True, False)
            if s:
                val_.append(s)
            else:
                if (status != 0):
                    # 角本中刻意把这项设为空(status==0)，则表示放弃当前项的注释，如：
                    # expression // 数据库 //
                    status, str_ = StrUtils.getStatementContent(str_, False, '')
                    val_.append(str_)
        if xMultiIndex:
            dict_x[key] = val_
        else:
            dict_x[key] = separator.join(val_)

    # 把titlesY放到Dataframe中，索引是它的行号，数据列被命名为：x0, x1, x2......
    ytitles = _src.get_value('Ytitles', [])
    df_y = pd.DataFrame.from_dict(dict_y, orient='index')
    columns_y = []
    for i in range(len_y):
        s = StrUtils.listGet(ytitles, i)
        if s:
            columns_y.append(s)
        else:
            columns_y.append('__x' + str(i))
    df_y.columns = columns_y

    index = []
    for i in range(_src.numY):
        index.append(i)

    columns = []
    for i in range(_src.numX):
        if xMultiIndex:
            if dict_x.get(i):
                columns.append(dict_x[i])
            else:
                # 未定义的title，生成一个
                tuple0 = ['__x' + str(len_y + i)]
                # (x0, nan) ==> (x0, '')
                for j in range(len_x-1):
                    if nonVal:
                        tuple0.append(nonVal)
                columns.append(tuple0)
        else:
            if dict_x.get(i):
                columns.append(dict_x[i])
            else:
                columns.append('__x' + str(len_y + i))

    try:
        if xMultiIndex:
            xtitles = _src.get_value('Xtitles', [])
            columns = pd.MultiIndex.from_tuples(columns, names=xtitles)
        else:
            xtitles = _src.get_value('Xtitles', '')
            if isinstance(xtitles, str):
                columns = pd.Index(columns, name=xtitles)
            else:
                columns = pd.Index(columns, name=xtitles[0])

        df_data = pd.DataFrame(data=_src.data, index=index, columns=columns)

        # 依照索引id，把df_x的内容合进来
        df = pd.merge(df_y, df_data, left_index=True, right_index=True, how='outer')
        if keepIndexInData:
            df = df.set_index(columns_y, drop=False)
        else:
            df = df.set_index(columns_y, drop=True)
        return df
    except (BaseException) as exc:
        print (str(exc))
        return pd.DataFrame()


def getResultVal(_src, y, x):
    '''
    示例：data.loc[0,('one','a')]
    :param y: 索引定位：(key1, key2...)
    :param x: 列定位：(column1, column2...)
    :return: 某一个元素的值
    '''
    if isinstance(y, list):
        y = tuple(y)
    if isinstance(x, list):
        x = tuple(x)

    if isinstance(y, int):
        return _src.data.iloc[y,x]
    else:
        return _src.data.loc[y,x]


def getResultTitles(df):
    '''
    程序示范：
    ylist, xlist = getResultTitles(df)
    y = 0
    for itemy in ylist:
        for item in itemy:
            if item.startswith('str')
                get y
                break
        y += 1

    getResultVal(y, x):
    '''
    return df.index.tolist(), df.columns.tolist()


def getJsonForEchart(_src, separator='/', nonVal='.', chartOptions={}):
    """
    生成数据，适合echart做此类型图：https://www.echartsjs.com/examples/editor.html?c=bar-stack
    {
        "legend": ["stata", "pandas", "r", "spss", "julia", "sas"],
        "xAxis": ["__x1", "数据指标ID/Data_num2", "__x3", "__x4", "__x5", "__x6", "数据指标ID/Data_num1"],
        "series": [
            [0.00, 0.47, 0.00, 0.00, 0.00, 0.00, 10.36],
            [0.00, 0.48, 0.00, 0.00, 0.00, 0.00, 7.21],
            [0.00, 0.50, 0.00, 0.00, 0.00, 0.00, 7.94],
            [0.00, 0.65, 0.00, 0.00, 0.00, 0.00, 11.79],
            [0.00, 0.60, 0.00, 0.00, 0.00, 0.00, 7.23],
            [0.00, 0.52, 0.00, 0.00, 0.00, 0.00, 8.81]
        ],
        "chartOptions": {}
    }
    """
    df = getResultDf(_src, xMultiIndex=False, yMultiIndex=False, separator=separator, nonVal=nonVal)

    legend = json.dumps(df.index.values.tolist(), ensure_ascii=False)
    xAxis = json.dumps(df.columns.values.tolist(), ensure_ascii=False)

    series = '['
    for i in range(_src.numY):
        series += '['
        for j in range(_src.numX):
            try:
                cell  = df.iloc[i, j]
                if isinstance(cell, float):
                    if math.isnan(cell):
                        series += ('0' + ',')
                    else:
                        series += ("{:.2f}".format(cell) + ',')
                else:
                    series += str(cell)
            except KeyError:
                series += '0,'

        series = series[:-1] + '],'
    series = series[:-1] + ']'

    if chartOptions:
        jsonText = json.dumps(chartOptions,ensure_ascii=False)
    else:
        jsonText = '{}'

    retstr = '{"legend":'+ legend + ',"xAxis":'+ xAxis + ',"series":' + series + ',"chartOptions":' + jsonText + '}'
    return (retstr)


def src_Dump(_src, file=None, keepData=False):
    '''
    将 Python 对象编码成字符串
    '''
    py_module = _src.py_module
    cursor = _src.cursor
    conn = _src.conn
    slaves = _src.slaves

    _src.py_module = None
    _src.cursor = None
    _src.conn = None
    _src.slaves = []
    _src0 = copy.deepcopy(_src)

    _src0.statusY = None

    if not keepData:
        _src0.data = None
        _src0.extdata = None
        _src0.moredata = None
        _src0.dictdata = None

    _src.py_module = py_module
    _src.cursor = cursor
    _src.conn = conn
    _src.slaves = slaves

    # _src.py_module，_src0.cursor, _src0.conn, 这三个对象不可dumps，
    # TypeError("Cannot serialize module object")
    # TypeError("Cannot serialize socket object")
    #_src0.cursor = cursor
    #_src0.conn = conn

    if file:
        pickle.dump(_src0, file)
        return ''

    return repr(pickle.dumps(_src0))


def src_Load(file, keepData=False):
    '''
    将已编码的字符串解码为 Python 对象
    '''
    try:
        if isinstance(file, str):
            _src = pickle.loads(ast.literal_eval(file))
        elif isinstance(file, (bytes, bytearray)):
            _src = pickle.loads(file)
        else:
            _src = pickle.load(file)

        if not keepData:
            _src.init_datas()
        return _src
    except:
        return None
